Skip to content

Conversation

@lightsta1ker
Copy link

Addresses #7937

@lightsta1ker lightsta1ker changed the title [WIP] Updating uninstrumented dice example [WIP] Updating dice example based on Updated Specification for the reference application Oct 30, 2025
@lightsta1ker lightsta1ker marked this pull request as ready for review October 30, 2025 17:43
@lightsta1ker lightsta1ker requested a review from a team as a code owner October 30, 2025 17:43
@lightsta1ker lightsta1ker changed the title [WIP] Updating dice example based on Updated Specification for the reference application Updating dice example based on Updated Specification for the reference application Oct 31, 2025
@pellared
Copy link
Member

pellared commented Nov 4, 2025

@lightsta1ker, I won't have time to review it further until I am back from KubeCon NA. Hopefully other @open-telemetry/go-approvers are going to help with reviews.

@lightsta1ker
Copy link
Author

Sure, @pellared . Thank you for the review & suggestions!

@pellared

This comment was marked as resolved.

@lightsta1ker

This comment was marked as resolved.

Copy link
Member

@flc1125 flc1125 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The normative review is completed, with additional notes:

According to the specification requirements, support for the OTLP exporter is needed. Currently, this part is not yet supported, but I believe it can be fully implemented through a separate PR.

@flc1125
Copy link
Member

flc1125 commented Nov 11, 2025

@lightsta1ker We still have some issues to resolve, including CI checks.

@lightsta1ker
Copy link
Author

@flc1125 I thought those checks were not relevant to this PR as it's not customer facing.

@pellared
Copy link
Member

@flc1125 I thought those checks were not relevant to this PR as it's not customer facing.

They are relevant.

@lightsta1ker
Copy link
Author

Updated with fixes for failing lint checks and error handling. Also rebased.

@lightsta1ker
Copy link
Author

@pellared Is changelog needed?

@pellared
Copy link
Member

@pellared Is changelog needed?

No

@pellared pellared added the Skip Changelog Allow PR to succeed without requiring an addition to the CHANGELOG label Nov 19, 2025
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
msg := "Parameter rolls must be a positive integer"
_ = json.NewEncoder(w).Encode(map[string]string{
Copy link
Member

@pellared pellared Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proper error handling is missing here (500 Internal Server Error).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pellared Isn't it refering to this line -
if rolls is set to an invalid input (not a number): status code 400 and {"status": "error", "message": "Parameter rolls must be a positive integer"} ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean if the json encoding fails then it is an internal server error.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that the chances of static map encoding failure is very less. Can I handle it like this?

if err != nil {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusBadRequest)

    msg := "Parameter rolls must be a positive integer"
    resp := map[string]string{
        "status":  "error",
        "message": msg,
    }

    if encErr := json.NewEncoder(w).Encode(resp); encErr != nil {
        logger.ErrorContext(r.Context(), "failed to write error JSON", "error", encErr)
        http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        return
    }

    logger.WarnContext(r.Context(), msg)
    return
}

@pellared pellared requested a review from Copilot November 19, 2025 11:58
Copilot finished reviewing on behalf of pellared November 19, 2025 12:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates the dice example application to align with the updated specification for the OpenTelemetry reference application. The changes modernize the API design, improve observability instrumentation, and add configurable deployment options.

Key Changes

  • Refactored HTTP handler to use query parameters (rolls and player) instead of path parameters, with JSON responses
  • Enhanced OpenTelemetry instrumentation with additional metrics (histogram for dice outcomes, gauge for last rolls value) and proper resource configuration
  • Added configurable port via APPLICATION_PORT environment variable for flexible deployment

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
examples/dice/uninstrumented/rolldice.go Refactored handler to parse query params, return JSON responses, added input validation with max rolls limit, and separated concerns with helper functions
examples/dice/uninstrumented/main.go Added configurable port support and updated route registration to single /rolldice endpoint
examples/dice/instrumented/rolldice.go Applied same refactoring as uninstrumented version, upgraded to math/rand/v2, added histogram and gauge metrics, improved telemetry context propagation
examples/dice/instrumented/otel.go Added resource configuration with environment, process, host, and SDK information; updated all provider constructors to accept resource parameter
examples/dice/instrumented/main.go Added configurable port support and simplified route registration to single endpoint

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +64
if err := json.NewEncoder(w).Encode(v); err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Printf("ERROR: %v", err)
}
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP status code should be set before writing the response body. Setting WriteHeader after json.NewEncoder(w).Encode() has already written data will have no effect, as headers are sent with the first write. Move the WriteHeader call before the Encode call.

Suggested change
if err := json.NewEncoder(w).Encode(v); err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Printf("ERROR: %v", err)
}
data, err := json.Marshal(v)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"status": "error",
"message": "Internal Server Error",
})
log.Printf("ERROR: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(data)

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +123
func writeJSON(ctx context.Context, w http.ResponseWriter, v any) {
if err := json.NewEncoder(w).Encode(v); err != nil {
w.WriteHeader(http.StatusInternalServerError)
logger.ErrorContext(ctx, "json encode failed", "error", err)
}
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP status code should be set before writing the response body. Setting WriteHeader after json.NewEncoder(w).Encode() has already written data will have no effect, as headers are sent with the first write. Move the WriteHeader call before the Encode call.

Copilot uses AI. Check for mistakes.
} else {
logger.DebugContext(r.Context(), "player rolled dice", "player", player, "results", results)
}
logger.InfoContext(r.Context(), "Some player rolled a dice.")
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Inconsistent logging format compared to the uninstrumented version. The uninstrumented version logs request details like "INFO: GET /rolldice?rolls=5 -> 200 OK" (line 50), while the instrumented version logs a generic message. Consider maintaining similar informative logging for consistency across both examples.

Suggested change
logger.InfoContext(r.Context(), "Some player rolled a dice.")
logger.InfoContext(
r.Context(),
"Request handled",
"method", r.Method,
"path", r.URL.Path+"?"+r.URL.RawQuery,
"status", "200 OK",
)

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +51
res, _ := resource.New(ctx,
resource.WithFromEnv(), // reads OTEL_SERVICE_NAME & OTEL_RESOURCE_ATTRIBUTES.
resource.WithProcess(),
resource.WithHost(),
resource.WithTelemetrySDK(),
)
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error returned by resource.New() is being silently ignored. This could lead to using a nil or incomplete resource, potentially causing issues with telemetry data. Either handle the error properly or at minimum log it if you intend to continue with a partial resource.

Suggested change
res, _ := resource.New(ctx,
resource.WithFromEnv(), // reads OTEL_SERVICE_NAME & OTEL_RESOURCE_ATTRIBUTES.
resource.WithProcess(),
resource.WithHost(),
resource.WithTelemetrySDK(),
)
res, resErr := resource.New(ctx,
resource.WithFromEnv(), // reads OTEL_SERVICE_NAME & OTEL_RESOURCE_ATTRIBUTES.
resource.WithProcess(),
resource.WithHost(),
resource.WithTelemetrySDK(),
)
if resErr != nil {
handleErr(resErr)
return shutdown, resErr
}

Copilot uses AI. Check for mistakes.

rollsAttr := attribute.Int("rolls", rolls)
span.SetAttributes(rollsAttr)
rollCnt.Add(ctx, 1, metric.WithAttributes(rollsAttr))
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The counter is being incremented by 1 regardless of the number of rolls performed. This doesn't accurately represent the total number of dice rolls. Consider incrementing by the number of actual rolls: rollCnt.Add(ctx, int64(rolls), metric.WithAttributes(rollsAttr))

Suggested change
rollCnt.Add(ctx, 1, metric.WithAttributes(rollsAttr))
rollCnt.Add(ctx, int64(rolls), metric.WithAttributes(rollsAttr))

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +43
results, err := rolldice(rolls)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Printf("ERROR: %v", err)
return
}
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Content-Type header before writing response. The handler should set w.Header().Set("Content-Type", "application/json") before calling writeJSON to properly indicate the response format, especially for error responses.

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +99
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Content-Type header before writing response. The handler should set w.Header().Set("Content-Type", "application/json") before calling writeJSON to properly indicate the response format, especially for error responses.

Suggested change
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
msg := "Internal server error"
_ = json.NewEncoder(w).Encode(map[string]string{
"status": "error",
"message": msg,
})

Copilot uses AI. Check for mistakes.

lastRollsGauge, err = meter.Int64ObservableGauge(
"dice.last.rolls",
metric.WithDescription("The last rolls value observed"),
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The description "The last rolls value observed" is unclear. Consider clarifying what "rolls value" means, e.g., "The number of dice rolled in the most recent request" to better describe what this gauge represents.

Suggested change
metric.WithDescription("The last rolls value observed"),
metric.WithDescription("The number of dice rolled in the most recent request"),

Copilot uses AI. Check for mistakes.
} else {
logger.DebugContext(r.Context(), "player rolled dice", "player", player, "results", results)
}
logger.InfoContext(r.Context(), "Some player rolled a dice.")
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The log message "Some player rolled a dice" is generic and doesn't add useful information beyond what's already logged in lines 105-108. Consider either making this message more specific (e.g., include the request status or outcome summary) or removing it to avoid redundant logging.

Suggested change
logger.InfoContext(r.Context(), "Some player rolled a dice.")

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Skip Changelog Allow PR to succeed without requiring an addition to the CHANGELOG

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants